#!/bin/sh
# shellcheck shell=dash disable=SC2169,SC2034,SC3010,SC3015 source=/dev/null
#
# startup script to identify the host hardware
#

identify_host() {

  # default/fallback values
  HM_HOST=""
  HM_MODE="NORMAL"
  HM_LED_GREEN=""
  HM_LED_GREEN_MODE1="none"
  HM_LED_GREEN_MODE2="heartbeat"
  HM_LED_RED=""
  HM_LED_RED_MODE1="timer"
  HM_LED_RED_MODE2="none"
  HM_LED_YELLOW=""
  HM_LED_YELLOW_MODE1="none"
  HM_LED_YELLOW_MODE2="none"

  # set GREEN_MODE1 and RED_MODE2 to the rootfs
  # device led trigger
  rootfs_trigger="$(/sbin/blkid --label rootfs | head -1 | sed -n 's/\/dev\/mmc.*\([[:digit:]]\)p[[:digit:]]$/mmc\1/p')"
  if [[ -n "${rootfs_trigger}" ]]; then
    HM_LED_GREEN_MODE1=${rootfs_trigger}
    HM_LED_RED_MODE2=${rootfs_trigger}
  fi

  # identify hardware model
  HWMODEL="n/a"
  if [[ -f /proc/device-tree/model ]]; then
    HWMODEL=$(cat /proc/device-tree/model)
  elif [[ -f /sys/devices/virtual/dmi/id/board_vendor ]]; then
    VENDOR=$(cat /sys/devices/virtual/dmi/id/board_vendor)
    NAME=""
    if [[ -f /sys/devices/virtual/dmi/id/board_name ]]; then
      NAME=$(cat /sys/devices/virtual/dmi/id/board_name)
    fi
    HWMODEL="${VENDOR} ${NAME}"
  elif [[ -f /sys/devices/virtual/dmi/id/sys_vendor ]]; then
    VENDOR=$(cat /sys/devices/virtual/dmi/id/sys_vendor)
    NAME=""
    if [[ -f /sys/devices/virtual/dmi/id/product_name ]]; then
      NAME=$(cat /sys/devices/virtual/dmi/id/product_name)
    fi
    HWMODEL="${VENDOR} ${NAME}"
  else
    MODEL=$(grep ^Model /proc/cpuinfo | cut -d" " -f2-)
    if [[ "${MODEL}" != "" ]]; then
      HWMODEL=${MODEL}
    fi
  fi

  # identify HM_HOST based on PLATFORM
  case "${PLATFORM}" in

    # RaspberryPi platform
    rpi*)
      # identify the RaspberryPi model based on HWMODEL (device tree)
      case "${HWMODEL}" in
        *'Pi 5 Model B'*)         HM_HOST="rpi5" ;; # Raspberry Pi 5 Model B
        *'Pi Compute Module 5'*)  HM_HOST="rpi5" ;; # Raspberry Pi Compute Module 5
        *'Pi 4 Model B'*)         HM_HOST="rpi4" ;; # Raspberry Pi 4 Model B
        *'Pi Compute Module 4'*)  HM_HOST="rpi4" ;; # Raspberry Pi Compute Module 4
        *'Pi 400'*)               HM_HOST="rpi4" ;; # Raspberry Pi 400
        *'Pi 3 Model B'*)         HM_HOST="rpi3" ;; # Raspberry Pi 3 Model B(+)
        *'Pi 3 Model A'*)         HM_HOST="rpi3" ;; # Raspberry Pi 3 Model A(+)
        *'Pi Zero 2 W'*)          HM_HOST="rpi3" ;; # Raspberry Pi Zero 2 W
        *'Pi Compute Module 3'*)  HM_HOST="rpi3" ;; # Raspberry Pi Compute Module 3
        *'Pi 2 Model B'*)         HM_HOST="rpi2" ;; # Raspberry Pi 2 Model B
        *'Pi Compute Module 2'*)  HM_HOST="rpi2" ;; # Raspberry Pi Compute Module 2
        *'Pi Compute Module')     HM_HOST="rpi1" ;; # Raspberry Pi Compute Module 1
        *'Pi Model B'*)           HM_HOST="rpi1" ;; # Raspberry Pi Model B/B+
        *'Pi Zero'|*'Pi Zero W'*) HM_HOST="rpi0" ;; # Raspberry Pi Zero / Zero W

        # No know RaspberryPi identified, fallback to rpi3
        *)
          HM_HOST="rpi3"
          echo "WARNING: could not identify RaspberryPi model (${HWMODEL}). Using 'rpi3' as fallback."
        ;;
      esac

      # setup RaspberryPi specific settings
      HM_LED_GREEN="/sys/class/leds/ACT"
      HM_LED_RED="/sys/class/leds/PWR"
      HM_LED_YELLOW=""

      # if we are running on a raspberrypi we
      # disable the HDMI port in case no cable is
      # connected. This is to save power, but also
      # to reduce potential interferences with the
      # GPIO-based RF modules
      hdmi_state=$(/usr/bin/tvservice -s | cut -d' ' -f2)

      # if the least significant bit is set the
      # HDMI cable seems to be unplugged or if
      # no HDMI display is listed using tvservice or
      # if no EDID info can be read from the display
      if [[ $(((hdmi_state & 0x01) == 1)) -eq 1 ]] ||
        ! /usr/bin/tvservice -l | grep -q "type HDMI" ||
        /usr/bin/tvservice -d /dev/null 2>&1 | grep -q "Nothing"; then
        /usr/bin/tvservice --off >/dev/null
        /usr/bin/vcgencmd display_power 0 >/dev/null
      fi

      # increase vm.min_free_kbytes to 16384 to increase stability
      # in memory critical situations
      sysctl -q vm.min_free_kbytes=16384
    ;;

    # ASUS Tinkerboard/TinkerboardS platform
    tinkerboard)
      HM_HOST="tinkerboard"

      # setup Tinkerboard specific settings
      HM_LED_GREEN="/sys/class/leds/led-0"
      HM_LED_RED="/sys/class/leds/led-2"
      HM_LED_YELLOW="/sys/class/leds/led-1"
    ;;

    # ODROID platform
    odroid-*)
      HM_HOST="odroid" # generic

      # identify the ODROID model
      case "${HWMODEL}" in
        # Hardkernel ODROID-C4
        *ODROID-C4*)
          HM_HOST="odroid-c4"
        ;;
        # Hardkernel ODROID-N2
        *ODROID-N2*)
          HM_HOST="odroid-n2"
        ;;
        # Hardkernel ODROID-C2
        *ODROID-C2*)
          HM_HOST="odroid-c2"
        ;;
      esac

      # setup ODROID specific settings
      HM_LED_GREEN="/sys/class/leds/blue:status"
      HM_LED_RED=""
      HM_LED_YELLOW=""
    ;;

    # OCI platform
    oci)
      HM_HOST="oci" # generic

      # save the HA supervisor token for later use
      if [[ -n "${HM_RUNNING_IN_HA}" ]]; then
        HM_SUPERVISOR_TOKEN=${SUPERVISOR_TOKEN}
      fi
    ;;

    # OVA platform
    ova)
      HM_HOST="ova" # generic

      # try to identify the used virtualization hypervisor
      hypervisor=$(/usr/bin/lscpu | grep 'Hypervisor vendor:' | awk '{print $3}')
      if [[ -n "${hypervisor}" ]]; then
        HM_HOST="ova-${hypervisor}"
      else
        # otherwise try to identify the system-manufacturer and use that one instead
        manufacturer=$(/usr/sbin/dmidecode -s system-manufacturer | awk '{print $1}' | tr -d ',')
        if [[ -n "${manufacturer}" ]]; then
          HM_HOST="ova-${manufacturer}"
        fi
      fi
    ;;

    # generic-x86_64
    generic-x86_64)
      HM_HOST="generic-x86_64"
    ;;

    # generic-aarch64
    generic-aarch64)
      HM_HOST="generic-aarch64"
    ;;

    # lxc platform
    lxc)
      HM_HOST="lxc"
    ;;

    # default fallback
    *)
      HM_HOST="${PLATFORM}"
      echo "WARNING: could not identify host platform. Using '${PLATFORM}' as fallback."
    ;;

  esac

  # make sure the LEDs are actually setup correctly
  if [[ -f "${HM_LED_GREEN}/trigger" ]]; then
    echo "${HM_LED_GREEN_MODE1}" >"${HM_LED_GREEN}/trigger"
  fi
  if [[ -f "${HM_LED_RED}/trigger" ]]; then
    echo "${HM_LED_RED_MODE1}" >"${HM_LED_RED}/trigger"
  fi
  if [[ -f "${HM_LED_YELLOW}/trigger" ]]; then
    echo "${HM_LED_YELLOW_MODE1}" >"${HM_LED_YELLOW}/trigger"
  fi
}

init_host() {
  # setup /dev_host for OCI/Docker and LXC environments
  if [[ "${HM_HOST}" =~ oci\|lxc ]]; then
    # when running in HA we just remount /dev to rw
    if [[ -n "${HM_RUNNING_IN_HA}" ]]; then
      # remount /dev as rw to allow multimacd to create
      # mmd_bidcos/mmd_hmip later on
      mount -o rw,remount /dev
    else
      # To avoid sharing the whole host /dev with the container we
      # mount devtmps in /dev_host and symlink the required devices
      # but not when running in HA
      mount -o noatime -t devtmpfs devtmpfs /dev_host
      if [[ -d "/dev_host" ]]; then
        for device in raw-uart raw-uart1 eq3loop mmd_bidcos mmd_hmip usb rtc rtc0 rtc1; do
          if [[ ! -e "/dev/${device}" ]]; then
            ln -s "/dev_host/${device}" "/dev/${device}"
          fi
        done
      fi
    fi
  fi
}

start() {
  echo -n "Identifying host system: "

  # make sure to load sysctl defaults from /etc/sysctl.conf
  [[ -f /etc/sysctl.conf ]] && /sbin/sysctl -p -q -e

  # source all data from /var/hm_mode and /VERSION
  [[ -r /var/hm_mode ]] && . /var/hm_mode
  [[ -r /VERSION ]] && . /VERSION

  # run identify routine
  identify_host

  # run init host routine
  init_host

  # save all HM_ env variables
  set | grep '^HM_' >/var/hm_mode

  if [[ -n "${HM_HOST}" ]]; then
    echo "${HWMODEL} (${HM_HOST}), OK"
  else
    echo "ERROR"
  fi
}

restart() {
  start
}

case "$1" in
  start)
    start
  ;;
  stop)
    # nothing
  ;;
  restart|reload)
    restart
  ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
esac

exit 0
